package common;

import interfaces.DataNodeDef;
import interfaces.NameNodeDef;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.zip.CRC32;
public class Utils {

    //TODO 改成配置文件
    public static final int startPort=30006;
    public static final int startTPort=36666;
    public static final int BLOCK_SIZE = 64*1024*1024;
    public static final int REPLICATE_NUM = 3;
    public static String remoteIp = "localhost";
    public static String localIp = "localhost";
    public static final int PACKET_SIZE = 1024 * 64 * 32;
    public static final String NN_IP = remoteIp;
    public static final int NN_PORT = 1099;

    /**
     *  将字节数组的校验放在数组的末尾的4个字节上。
     *  考虑效率问题，字节数组的size=实际大小+4.
     *  本函数并不新建字节数组
     * @param block
     * @return
     */
//    public static void addCRC(byte[] block){
//        CRC32 crc32 = new CRC32();
//        assert block.length == BLOCK_SIZE+4;
//        crc32.update(block,0, block.length-4);
//        long value = crc32.getValue();
//        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
//        byte[] array = buffer.putLong(value).array();
//        for(int i=0;i<4;i++){
//            block[i+block.length-4] = array[i+4];
//        }
//    }

//    public static byte[] addCRC(byte[] block){
//        CRC32 c = new CRC32();
//        c.update(block);
//        int  res = (int)c.getValue();
//        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
//        System.out.println("res"+res);
//        byte[] array = buffer.putInt(res).array();
//        byte[] array4 = new byte[4];
//        System.arraycopy(array,0,array4,0,4);
//        return unitBytes(block,array4);
//    }
//    /**
//     *  检测字节数组的crc校验码与后四个字节比对
//     *  未改变返回True
//     * @param block
//     * @return
//     */
//    public static boolean checkSum(byte[] block){
//        CRC32 crc32 = new CRC32();
//        crc32.update(block,0,block.length-4);
//        long value = crc32.getValue();
//        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
//        buffer.put(block,block.length-4,4);
//        buffer.flip();
//        return ((int)value==buffer.getInt());
//    }

    /**
     *  获得DNStub
     * @param ip dataNode ip
     * @param port dataNode 端口
     * @return DNStub
     */
    public static DataNodeDef getDNStub(String ip, int port) {
        try {
            DataNodeDef DNStub = (DataNodeDef) Naming.lookup("//" + ip + ":" + port + "/" + "DN" + ip + port);
            return DNStub;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("ClientImpl: Error connecting to DN");
            return null;
        }
    }

    public static NameNodeDef getNNStub(String ip,int port){
        try {
            NameNodeDef NNStub = (NameNodeDef) Naming.lookup("//localhost" + ":" + port + "/NN");
            return NNStub;
        } catch (NotBoundException | MalformedURLException | RemoteException e) {
            e.printStackTrace();
            System.out.println("Error connecting to NN");
            return null;
        }
    }

    public static byte[] unitBytes(byte[] byte1,byte[] byte2){
        byte[] unitByte = new byte[byte1.length+byte2.length];
        System.arraycopy(byte1,0,unitByte,0,byte1.length);
        System.arraycopy(byte2,0,unitByte,byte1.length,byte2.length);
        return  unitByte;
    }

    public static byte[] addCRC(byte[] block){
        CRC32 c = new CRC32();
        c.update(block);
        int  res = (int)c.getValue();
        ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
        return buffer.putInt(res).array();
    }


    public static boolean checkSum(byte[] block){
        CRC32 crc32 = new CRC32();
        crc32.update(block,0,block.length-4);
        int value = (int) crc32.getValue();
        ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
        buffer.put(block,block.length-4,4);
        buffer.flip();
        int anInt = buffer.getInt();
        return value == anInt;
    }

    public static void fileCopyWithFileChannel(File fromFile, File toFile) {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        FileChannel fileChannelInput = null;
        FileChannel fileChannelOutput = null;
        try {
            fileInputStream = new FileInputStream(fromFile);
            fileOutputStream = new FileOutputStream(toFile,true);
            //得到fileInputStream的文件通道
            fileChannelInput = fileInputStream.getChannel();
            //得到fileOutputStream的文件通道
            fileChannelOutput = fileOutputStream.getChannel();
            //将fileChannelInput通道的数据，写入到fileChannelOutput通道
            fileChannelInput.transferTo(0, fileChannelInput.size(), fileChannelOutput);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileInputStream != null)
                    fileInputStream.close();
                if (fileChannelInput != null)
                    fileChannelInput.close();
                if (fileOutputStream != null)
                    fileOutputStream.close();
                if (fileChannelOutput != null)
                    fileChannelOutput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
